test: the ledger records which majors each check exists on (#1010) - #1019
Conversation
f5b09c8 to
6fc13c1
Compare
jdatcmd
left a comment
There was a problem hiding this comment.
Approving. The migration is derived rather than assumed, and I checked the arithmetic against main rather than the PR body.
main 204 differential + 916 harness_selftest + 46 native_join_runtime_filter = 1166
pr1019 204 + 916 + 46 = 1166
diff 1166 insertions, 1166 deletions -- one field added per line, no row moved
census 1164 = never rows 1164, both sides; ceiling 249 -> 249
The part that could have been a false claim is not one. Every row migrates to 15;16;17;18;19, which the migration cannot know a priori — and you did not assume it. You ran a five-major matrix, 252 suite logs each, and the three covered suites came back major-invariant with those exact counts. That is the difference between a migration that records a measurement and one that records a hope.
And refusing to widen coverage was the right call. 6629 observed checks outside the three covered suites, deliberately not seeded, because taking the ledger to 7795 rows would make several thousand checks gate-enforced in a diff nobody could review. I seeded differential today precisely because that number moves one suite at a time and stays reviewable; doing all 252 in the same change as a format migration would have buried both.
The token validation matters more than it looks — pg18 refused as a major, unknown carried as a real member rather than a courtesy. A ledger keyed on a field whose vocabulary is not policed would quietly grow a second spelling of the same major and the intersection logic would silently stop matching.
One thing I verified because it is the failure this whole issue is about: the fourth category still says "this run does not contain them, so it cannot speak about them", so the scope gains an intersection and nothing else. Absence still does not mean removal. That is the invariant I would have been most worried about a majors field quietly breaking.
Merging when CI settles.
commandprompt#1013 landed between this branch going green and being merged, so the merge commit could not be created. Second rebase of this PR today; both were caused by merges of mine, not by anything the author did. TWO CONFLICTS. CHANGELOG.md: two entries, neither a revision of the other. Both kept. check_ledger_budget.txt: the census. This branch said 1162, main said 1164, and BOTH ARE NOW WRONG -- the ledger auto-merged and holds rows from both sides. The number is DERIVED from the merged file rather than picked from either parent, which is the case commandprompt#1004 exists for and commandprompt#952 before it: two branches each re-derive a census from the same base, the ledger takes both sets of rows, and the budget keeps whichever side won the conflict. rows 1179 | never 1171 | ever red 8 gate: census stated 1171, ledger holds 1171: they agree duplicate (suite, part, name) keys: 0 MY FIRST DERIVATION WAS WRONG AND SAID SO OUT LOUD. I counted `$5=="never"` and got ZERO against 1179 rows. commandprompt#1019 adds the majors field and moves last-red to field 5, but commandprompt#1019 is not merged: this tree is still five fields, and last-red is field 4. A count of zero never-red rows on a tree with eight ever-red is not a plausible number, which is the only reason I looked. Had the two formats differed by something less obvious than 1171 against 0, the budget would have shipped a lie the gate would then have refused on a correct tree. No code change; the C in this PR is untouched by the merge. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EbyGSaU93XYQr8aH4NrUiw
|
This is red on The cause
This PR makes a ledger row six fields. So Reproduced against your tool with your fixture, built exactly as So: Why it is worth a sentence beyond the fixThe failing arms are not about majors at all. They are #1015's distance-from-HEAD arms, and they broke because a format migration moved a field under fixtures that belong to a different feature. That is the same shape as the The grep in those arms is what made it legible — I did not push the fix to your branch. Two |
…ompt#1010) The major is a FIELD, not part of the key, and that is the design rather than an implementation detail. A check's existence depends on the major, so a ledger that cannot say where a check exists cannot tell a deleted check from one that never ran here. analyze_differential.sh:61 emits ONE record on PG15-17 and a suite's worth on PG18+; fk_referencing.sh:287 emits DIFFERENT CHECK NAMES in its two branches. It does not follow that the major belongs in the key. Measured on a full matrix at 4d7c75a, 252 suites on PG15 and PG18: 6367 of 6472 checks are identical on both majors and 105 exist on exactly one. A (major, check) key would hold 6472 x 5 = 32,360 rows to express those 105 -- about 247 duplicate rows for every row that differs, each a second copy of one observation. Keeping the key at (suite, part, name) also keeps checks_never_observed_red counting CHECKS. Under a pair key it would count pairs, and "5800 checks" in a tree holding 1150 of them is a number that lies by its own name. The field is a sorted ;-separated SET and it ACCUMULATES. A plain assignment was measured doing the wrong thing to last-red on commandprompt#918: merging a PG15 log after a PG18 log must not make the check stop existing on 18, because the order somebody merges logs in is not a fact about the code. NO WILDCARD. "Every major observed" would change meaning the day a major joins the matrix, inheriting a claim nothing measured. WHAT THIS FIXES is orphan-scan, not gate. The gate refuses a check in the LOG the ledger has not seen, and a PG18-only check does not appear in a PG15 log, so it stayed correct by never being asked. orphan-scan asks the opposite question, and a PG18-only row is exactly what a deleted check looks like on PG15. It was saved only by the SKIP rule -- analyze_differential emits a check_skip so its part was unprunable, while fk_referencing emits check and has no SKIP at all. The fourth category already said the true thing, so the scope gains an intersection and nothing else: no new category and no grandfather rule. The gate also cannot refuse a check on a major it holds no rows for, for the same reason it cannot in a suite it has never seen. The documented census derivation moves from $4 to $5 in check_ledger_budget.txt, and both CHANGELOG entries that state it are corrected visibly rather than silently -- one of them says in its own text that the command was an INSTRUCTION and that is why its first wrong version is still shown. The committed ledger is migrated in the next commit, from a five-major run. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Uf6UoeBRZYLQZa4KxNiw8a
I justified the `unknown` token by grepping harness_selftest.sh for PGC_MAJOR,
finding none, and concluding its 907 records all carry it. That was written into
eight places before one awk over a log already on disk disproved it:
grep '^RESULT\t' pg18-harness_selftest.log | awk -F'\t' '{c[$6]++} END {...}'
18: 916
All 916 carry the real major. The suite does not reference PGC_MAJOR, but 10 of
its 46 parts call pgc_setup -- which sets it -- and parts are sourced into ONE
shell, so the value persists to every later record. Absence from the source was
never the question.
The truth is 14 OTHER suites: they need no cluster, so they never call pgc_setup,
and every record they emit carries `unknown`. Measured on a full pg18 matrix,
544 of 6753 records: audit, concurrency, decode_interrupts, hilbert_curve,
objstore_stash_recovery, phase2-6, smoke, unique_conc, update_conc, wal_envelope.
None of the three suites the ledger covers today is one, so every migrated row
will name real majors; the token matters for the suites coverage reaches next.
A consequence only the measurement showed: because the value is set by whichever
part runs first, `unknown` versus a number is ORDER-DEPENDENT in any suite that
sources parts into one shell. On pg18 all 916 of harness_selftest's records named
the major, so the first pgc_setup precedes the first record today. A part added
ahead of it would not, and the ledger expecting a number would refuse it.
Also corrects orphan-scan's docstring, which named part 340's stand-in skip name
as a present-tense blocker to arming it. commandprompt#994 and commandprompt#998 removed that: part 340 now
calls check_skip under each premise's own name and the stand-in survives only in a
comment. Arming is now a decision rather than a dependency, and it is not taken
here -- filed as commandprompt#1015, because "the one blocker I measured is gone" is not the
same claim as "no blocker remains".
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uf6UoeBRZYLQZa4KxNiw8a
Derived from a five-major matrix on step 1's tree (a0b2c00), 252 suite logs per major, 6660-6787 records each. Not a merge: the committed ledger is five fields and step 2's read_ledger needs six, and a five-field compatibility path in the tool would leave a branch nobody removes. rows 1166 -> 1166 (carried 1166, added 0) census 1164 -> 1164 (unchanged) ever red 2 -> 2 (both carried, with their dates) fields 5 -> 6 major sets held 1166 x "15;16;17;18;19" Every row claims all five majors, because all three covered suites emit the same checks on every one: harness_selftest 916, differential 204, native_join_runtime_filter 46, identical on 15/16/17/18/19. So the census does not move and the diff is one field added per line. THE MEASURED CASE FOR THE SET. Under a (major, check) key those same 1166 checks would be 5830 rows -- exactly 5x, 4664 of them second copies of one observation. Across the whole tree the logs hold 7795 distinct checks whose major sets would be 31357 rows under a pair key, a 4x multiplier, and the distribution says why a set is the right shape: 5863 15;16;17;18;19 checks identical on every major 545 unknown suites that need no cluster, so never call pgc_setup 285 19 \ 251 18 | 250 per major of these are fuzz, whose names 250 15, 16, 17 each | interpolate a random fixture (commandprompt#1011) 93 18;19 / 3 15;16;17 2 15;16;17;18 2 17;18;19 1 15;16 COVERAGE IS NOT WIDENED HERE, and the migration refuses to. The logs carry all 252 suites; seeding them would take the ledger to 7795 rows and drop suites_not_covered from 249 to nearly nothing, making several thousand checks gate-enforced in a diff nobody could review. 6629 observed checks outside the three covered suites were deliberately not seeded. The migration also fails closed rather than guessing: a committed row observed on no major refuses the whole run and prints the rows, because absence is not removal and a placeholder major would be a claim nothing measured. On this tree it refused nothing -- all 1166 were observed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Uf6UoeBRZYLQZa4KxNiw8a
47e3191 to
84bbe88
Compare
…andprompt#1010) Found by running harness_selftest on pg15 rather than by reading: seven arms in the --against prior-budget family went red, all with rc=2, which is the tool's integrity failure. Both fixtures write a ledger to a path that is neither *.tsv nor $_ledger -- "$_dist/led" and "$_rr/led" -- so the sweep that widened every other fixture matched neither, twice. The lesson is the same one the format transform taught earlier in this change and I did not carry far enough: a sweep keyed on a FILENAME PATTERN cannot find a fixture named something else. The sweep that found these counts tab-separated FIELDS in every printf that writes a date or `never`, which is a property of the content rather than of the path.
84bbe88 to
9389792
Compare
linuxhikerpm
left a comment
There was a problem hiding this comment.
CI is red for a reason the tree itself states. At 84bbe886f43cb67e2b4cf526e352c1739e156a55 test/check_ledger.tsv is still five fields (differential\tdifferential\tagg avg\tnever\t-). The tool now requires six, so:
- pytest-guards:
every committed row has six fields: got 1179 want 0(andnever=0because it is reading the mutations column as last-red) - suites:
check_ledger.tsv:1: a ledger row needs 6 fields, got 5, thenharness_selftest=FAIL
The migration commit message says the file was rewritten to suite, part, name, majors, last-red, mutations. That file is not in this PR's diff. Re-derive it against current main (which now also carries native_join_vector_agg from #1012) rather than merging past a 5-field ledger the new reader refuses.
Do not merge.
|
Right about What the current head carries: Re-derived against current main, including the suite #1012 added, which is the part Five-major matrix, 253 suite logs per major. All four covered suites are major-invariant -- The 2 dropped rows are the two checks this change RENAMED ( On "rather than merging past a 5-field ledger": that is exactly what went wrong and it is And the guard you would reach for already exists: part 410's Worth one note on what the census number means now, since it is the thing most likely to be |
Step 2 of #1010. Depends on #1013 (the first two commits) -- do not merge this before it
if you want them reviewed apart. The three commits that are this change are
ce2be2e5,f5b09c80,0812c57d.The major is a FIELD, not part of the key
A check's existence depends on the major, so the ledger has to record where a check
exists. It does not follow that the major belongs in the key, and the measurement decides it.
Full matrix at
4d7c75ae, 252 suites on PG15 and PG18: 6367 of 6472 checks are identicalon both majors and 105 exist on exactly one. A
(major, suite, part, name)key would hold5 copies of one observation for 98% of the file.
On today's coverage, measured from the migration itself:
Across the whole tree the five-major logs hold 7795 distinct checks, which a pair key would
store as 31357 rows.
Keeping the key also keeps
checks_never_observed_redcounting CHECKS. Under a pair keyit would count pairs, and "5800 checks" in a tree holding 1150 of them is a number that lies
by its own name -- the defect
check_ledger_budget.txtexists to argue against. No budgetkey is renamed and the census does not move.
The field is a sorted
;-separated SET and it accumulates. A plain assignment wasmeasured doing the wrong thing to last-red on #918: merging a PG15 log after a PG18 log must
not make the check stop existing on 18, because the order somebody merges logs in is not a
fact about the code.
No wildcard. "Every major observed" would change meaning the day a major joins the
matrix, inheriting a claim nothing measured.
What it fixes is
orphan-scan, notgateThe gate refuses a check in the LOG the ledger has not seen, and a PG18-only check does not
appear in a PG15 log -- so it stayed correct by never being asked.
orphan-scanasks theopposite question, and a PG18-only row is exactly what a deleted check looks like on PG15.
It was saved only by the SKIP rule, and that was luck:
analyze_differentialemits acheck_skipon PG15-17 so its part was unprunable, whilefk_referencing:287emitscheckand has no SKIP at all -- 24 keys shared, 2 only on PG18, 1 only on PG15. Once thatsuite is seeded, a PG15 run would have called its two PG17+ checks deleted.
The fourth category already said the true thing ("this run does not contain them, so it
cannot speak about them"), so the scope gains an intersection and nothing else: no new
category and no grandfather rule.
The gate also cannot refuse a check on a major it holds no rows for, for the same reason it
cannot in a suite it has never seen -- otherwise adding PG20 reddens every check at once,
which is a gate somebody turns off. It says out loud when it is not enforcing.
The migration
Derived from a five-major matrix on step 1's tree, 252 suite logs per major:
Every row claims all five majors because all three covered suites are major-invariant:
harness_selftest916,differential204,native_join_runtime_filter46, identical on15/16/17/18/19. So the diff is one field added per line.
It fails closed rather than guessing: a committed row observed on no major refuses the
whole run and prints the rows, because absence is not removal and a placeholder major would
be a claim nothing measured. It refused nothing here -- all 1166 were observed.
It also refuses to widen coverage. The logs carry all 252 suites; seeding them would take
the ledger to 7795 rows and drop
suites_not_coveredfrom 249 to nearly nothing, makingseveral thousand checks gate-enforced in a diff nobody could review. 6629 observed checks
outside the three covered suites were deliberately not seeded.
Test plan
accumulates; a run speaks only for the majors a row claims; the gate cannot refuse on
an uncovered major. Each carries a CONTROL -- without them the first proves only that
nothing is ever an orphan and the third only that the gate refuses nothing.
plus the invalid-major and no-major row refusals with an
unknowncontrol.docs_style.shPASSED.record format and this changes only the ledger the gate reads.
A correction carried in the second commit
I justified the
unknowntoken by greppingharness_selftest.shforPGC_MAJOR, findingnone, and concluding its 907 records carry it. That went into eight places before one awk
over a log already on disk disproved it: all 916 carry the real major, because 10 of its 46
parts call
pgc_setupand parts share one shell. The truth is 14 other suites that needno cluster -- 544 of 6753 records. All eight are corrected.
The measurement also showed something I would not have guessed:
unknownversus a number isorder-dependent in any suite sourcing parts into one shell. A part added ahead of the
first
pgc_setupwould emitunknownwhere the ledger expects a number.Also corrects
orphan-scan's docstring, which named part 340's stand-in skip name as apresent-tense blocker to arming it. #994 and #998 removed that. Arming is now a decision
rather than a dependency, and it is not taken here -- filed as #1015, because "the one
blocker I measured is gone" is not the same claim as "no blocker remains".
🤖 Generated with Claude Code
https://claude.ai/code/session_01Uf6UoeBRZYLQZa4KxNiw8a